<template>
  <div class="select-data-container">
    <div class="select-box" >
      <el-select
        v-model="labelValue"
        v-bind="$attrs"
        :disabled="disabled || !selectAble"
        :filterable="subType === 'select'"
        :popper-class="subType === 'select'?'':'select-tree'"
        :filter-method="searchAbel ? dataFilter : null"
        v-on="$listeners"
        contenteditable="false"
        @change="dataChange"
        @focus.prevent.stop="alertDialog"
        @blur.prevent.stop="alertDialog"
        style="display: block;"
        clearable
        ref="select"
        @remove-tag="removeTag"
        @visible-change="visibleChange"
        :allow-create="canInput"
        :default-first-option="canInput"
        onmouseover="this.title = this.getElementsByClassName('el-input__inner')[0].value"
      >
        <el-option
          v-for="o in mapSelectOptions"
          :key="o.id"
          :label="o.label"
          :value="o.value"
          :disabled="o.disabled || $attrs.multiple"
        >
          <template v-if="labelFields.length">
            <span v-for="(itm, index) in labelFields" :key="index">{{o[itm]}}</span>
          </template>
        </el-option>
      </el-select>
      <template v-if="!disabled">
        <i
          class="icon el-icon-search active-search-icon"
          v-show="searchIconVisible"
          slot="suffix"
          @click.stop="alertDialog"
        ></i>
      </template>
    </div>
    <search-dialog-object-type2
      :visibleValue.sync="dialogShow"
      :props="props"
      :url="url"
      :title="title"
      ref="dialog2"
      :options.sync="optionsData"
      :params="params"
      :paramsMap="paramsMap"
      :headers="headers"
      :responseType="responseType"
      :getDictResultMap="getDictResultMap"
      :getDictSuccessStatus="getDictSuccessStatus"
      :searchKey="searchKey"
      :labelFields="labelFields"
      v-bind="$attrs"
      v-on="bindListeners"
      :value="value"
      @dataChange="dataChange"
      @dialogDataChange="dialogDataChange"
    >
      <template slot="appendSearch" >
        <slot name="appendSearch" :data="params"></slot>
      </template>
    </search-dialog-object-type2>
  </div>
</template>

<script>
  import searchDialog from './dialog/searchDialog';
  import searchDialogObjectType2 from './dialog/searchDialogObjectType2';
  import personDialog from './dialog/personDialog';
  import Label from './directives/label';
  import BaseRequestComponent from "../BaseRequestComponent";
  import arr from "../../../../utils/function/arr";
  export default {
    name: "ZbFormSelectDataObject",
    extends:BaseRequestComponent,
    components: {searchDialog,personDialog,searchDialogObjectType2},
    directives: { Label },
    filters: {},
    mixins: [],
    props: {
      value:  [Object,Array,Number,String],
      filterable: Boolean,
      maxCount:null,
      url: {
        type: String,
        default: ""
      }, // 请求地址
      canInput: {
        type: Boolean,
        default: false
      }, // 是否可以输入
      selectAble: {
        type: Boolean,
        default: true
      }, // 是否可以选择
      params: {
        type: Object,
        default: () => ({
          pageNum: 1,
          pageSize: 20,
        })
      },
      paramsMap: {
        type: Object,
        default: () => ({
          pageNum: 'pageNum',
          pageSize: 'pageSize',
        })
      },
      // 弹窗的类型
      dialogType: {
        type: Number,
        default:() =>1
      },
      options: Array, // 选项
      props: {
        type: Object,
        default: () => ({
          label: "label",
          value: "value",
        })
      },
      title: {
        type: String,
        default: "数据选择"
      },
      disabled: Boolean,
      dataField: String, // 返回结果中显示的字段名
      // 弹出选则框类型 select treeSelect
      subType: {
        type: String,
        default: "select"
      },
      labelText: [String, Number, Array], // 无下拉选项时显示的名称
      // 下拉选项显示字段
      labelFields: {
        type: Array,
        default: () => []
      },
      searchAbel: Boolean, // 开启搜索
      searchKey: {
        // 查询请求的key
        default: "nameOrNumber"
      },
      searchIconVisible: {
        // 显示搜索图标
        type: Boolean,
        default: false
      },
      searchDialogEnable: {
        // 是否开启显示搜索框
        type: Boolean,
        default: true
      },
      autoFirst: {
        // 是否自动选择第一个
        type: Boolean,
        default: false
      },
      asyncLoad: {
        // 是否是同步加载数据 同步为 true（当列表有多个该组件渲染时，只会加载一次） 异步为 false
        type: Boolean,
        default: false
      },
      dynamicLableText:[String, Number, Array],
    },
    data() {
      return {
        optionsData: this.options || [],
        labelValue: "",
        dialogShow: false,
        storeMapSelectOptions:null
      };
    },
    created() {
      // 临时存储的数据
      this.storeMapSelectOptions = this.mapSelectOptions
    },
    computed: {
      bindListeners() {
        const events = this.$attrs.listeners
        return Object.assign(this.$listeners,events)
      },
      mapSelectOptions() {
        const { label, value, number } = this.props;
        const options = this.optionsData.map(item => {
          item.label = item[label];
          item.value = item[value];
          return item;
        });
        if (this.$attrs.multiple && this.value instanceof Array) {
          // 有默认值
          this.value.map(item=>{
            let a = {}
            a.value = item[this.props.value]
            a.label = item[this.props.label]
            a.id = item[this.props.value]
            this.$set(item, 'value', item[this.props.value]);
            this.$set(item, 'label', item[this.props.label]);
            this.$set(item, value, item[this.props.value]);
            this.$set(item, label, item[this.props.label]);
            options.push(item)
          })
        } else if (
          !this.$attrs.multiple &&
          options.findIndex(i => i[this.props.value] === this.value) === -1
        ) {
          options.push(this.value);
        }
        return options;
      }
    },
    watch: {
      value: {
        handler(val) {
          if (this.inOptions() || !this.createdRequest){
            this.labelValue = arr(val).pluck(this.props.value).all()
          }else{
            this.labelValue = null
          }
        },
        immediate: true
      },
      url: {
        handler(val) {
          if (val && this.subType === "select" && !this.$attrs.cascade) {
            if (this.createdRequest){
              this.getAsyncOptions();
            }
          }
        },
        immediate: true
      },
      params: {
        handler(val, oldVal) {
          if (val !== oldVal && this.subType === "select") {
            if (this.createdRequest){
              this.getAsyncOptions();
            }
          }
        },
        deep: true
      },
    },
    methods: {
      // 判断 value 是否在 数组 arr 中
      inOptions(){
        if (!this.$attrs.multiple){
          for (let i = 0; i < this.mapSelectOptions.length; i++) {
            if (this.mapSelectOptions[i].value === this.value){
              return true
            }
          }
          return false
        }
        return true
      },
      // 获取选项数据
      getAsyncOptions() {
        this.optionsData = []
        const key = encodeURIComponent(
          this.url + JSON.stringify(this.params) + this.$attrs.method
        );
        // const key = encodeURIComponent(this.url + this.params + this.$attrs.method)
        const optionsSelect = this.$zbStore.state.optionsCache.data;
        // 表示查询的是这个接口是否被请求
        const count = this.$zbStore.state.optionsCache.count;
        const index = optionsSelect.findIndex(item => item.key === key);
        if (index !== -1) {
          this.optionsData = optionsSelect[index].options;
          return;
        } else {
          if (!this.asyncLoad){
            // 异步加载
            this.getOptionsDictAsync(optionsSelect,key)
          }else{
            if (count[key] === undefined){
              return this.getOptionsDictSync(optionsSelect,key)
            }
            // 有一次请求，但是请求没有完成，就index!=-1, (count=requesting || count=undefined)
            if (count[key] ==='requesting'){
              // 会循环的取这个 optionsSelect 数据以及赋值操作，直到取出数据为止，防止发生多次渲染，多次调用接口
              setTimeout(()=>{
                this.getAsyncOptions()
              },200)
            }
            // 有一次了,请求完成了，就index!=-1, count=1
            if (count[key] ==='requested'){
              this.optionsData = optionsSelect[index].options;
              return;
            }
          }
        }
      },
      // 获得选项的字典 同步
      async getOptionsDictSync(optionsSelect,key){
        this.$zbStore.dispatch("setCatchCount", {key:key,status:'requesting'});
        return await this.getDict(this.url, this.params, this.$attrs.method).then(res => {

          let status = eval(`res.${this.getDictResultMap.status}`)
          let data = eval(`res.${this.getDictResultMap.data}`)
          let list = eval(`res.${this.getDictResultMap.list}`)
          if (status === this.getDictSuccessStatus) {
            // 是否过滤数据
            if (this.$listeners.filterData) this.$emit("filterData",res);
            if (data && list && list instanceof Array) {
              this.optionsData = list || [];
              if (this.autoFirst) {
                // 自动选择第一个
                this.labelValue = list[0][this.props.value];
                this.dataChange(list[0][this.props.value]);
                this.$emit("input", this.labelValue);
              }
            } else if (data instanceof Array && data.length) {

              this.optionsData = data || [];
              if (this.autoFirst) {
                this.labelValue = data[0][this.props.value];
                this.dataChange(data[0][this.props.value]);
                this.$emit("input", this.labelValue);
              }
            } else {
              // 防止查询条件更新后查不到数据的情况下 清空下拉列表
              this.optionsData = [];
              this.labelValue = "";
            }
            if (this.dataField) {
              this.optionsData = this.optionsData.map(
                itm => itm[this.dataField]
              );
            }
            const obj = {
              key: key,
              options: this.optionsData,
              count:0
            };
            this.$zbStore.dispatch("setCatch", obj);
            this.$zbStore.dispatch("setCatchCount", {key:key,status:'requested'});
          }
        });
      },
      // 获得选项的字典 异步
      getOptionsDictAsync(optionsSelect,key){
        return this.getDict(this.url, this.params, this.$attrs.method).then(res => {
          let status = eval(`res.${this.getDictResultMap.status}`)
          let data = eval(`res.${this.getDictResultMap.data}`)
          let list = eval(`res.${this.getDictResultMap.list}`)
          if (status === this.getDictSuccessStatus) {
            // 是否过滤数据
            if (this.$listeners.filterData) this.$emit("filterData",res);
            if (data && list && list instanceof Array) {
              this.optionsData = list || [];
              if (this.autoFirst) {
                // 自动选择第一个
                this.labelValue = list[0][this.props.value];
                this.dataChange(list[0][this.props.value]);
                this.$emit("input", this.labelValue);
              }
            } else if (data instanceof Array && data.length) {

              this.optionsData = data || [];
              if (this.autoFirst) {
                this.labelValue = data[0][this.props.value];
                this.dataChange(data[0][this.props.value]);
                this.$emit("input", this.labelValue);
              }
            } else {
              // 防止查询条件更新后查不到数据的情况下 清空下拉列表
              this.optionsData = [];
              this.labelValue = "";
            }
            if (this.dataField) {
              this.optionsData = this.optionsData.map(
                itm => itm[this.dataField]
              );
            }
            const obj = {
              key: key,
              options: this.optionsData
            };
            this.$zbStore.dispatch("setCatch", obj);
          }
        });
      },
      // 弹出选择框
      alertDialog() {
        if (!this.searchDialogEnable) return;
        if (!this.disabled) {
          this.dialogShow = true;
        }
      },
      visibleChange(e){
        this.$nextTick(function () {
          let elementsByClassName = document.getElementsByClassName("el-select-dropdown");
          if (elementsByClassName && elementsByClassName.length){
            for (let i = 0; i < elementsByClassName.length; i++) {
              elementsByClassName[i].setAttribute("style", "display:none")
            }
          }
        })
      },
      // dataChange 事件 返回选中的对象
      dataChange(val) {
        if (this.maxCount && val.length > this.maxCount){
          val.pop()
          return this.$message.info(`最多只能选择${this.maxCount}项`)
        }
        const { value } = this.props;
        if(val instanceof Array && val.length){

          const newArrayValue = val.map(ele => {
            return this.mapSelectOptions.find(i => i[value] === ele);
          });
          let newArrayLabel = this.mapSelectOptions.filter(i => val.includes(i[value]))
          newArrayLabel =  arr(newArrayLabel).pluck(this.props.label).all()

          if (this.bindListeners.dataChange){
            this.bindListeners.dataChange(newArrayValue)
          }
          if (this.$listeners.dataChange && !this.bindListeners.dataChange){
            this.$emit( "dataChange",newArrayValue);
          }
          this.$emit('input',newArrayValue)
        }else{
          let item = this.optionsData.find(i => i[value] === val)
          if (this.bindListeners.dataChange){
            this.bindListeners.dataChange(item)
          }
          if (this.$listeners.dataChange && !this.bindListeners.dataChange){
            this.$emit( "dataChange",item);
          }
          this.$emit('input',item)
        }
      },
      // 移除 事件 返回选中的对象
      removeTag(val) {
        let dialog2 = this.$refs.dialog2;
        if (dialog2.disabledRow && dialog2.disabledRow.length){
          dialog2.disabledRow = dialog2.disabledRow.filter(item=>item[dialog2.props.value]!==val)
        }
        if (dialog2.checkedValuesAllObj){
          let keys = Object.keys(dialog2.checkedValuesAllObj)
          for (let i = 0; i < keys.length; i++) {
            let checkedValuesAllObjElement = dialog2.checkedValuesAllObj[keys[i]];
            if (checkedValuesAllObjElement && checkedValuesAllObjElement.length){
              dialog2.checkedValuesAllObj[keys[i]] = checkedValuesAllObjElement.filter(item=>item[dialog2.props.value]!==val)
            }
          }
        }
      },
      // change事件
      dialogDataChange(data) {
        const { value } = this.props;
        if (this.$attrs.multiple && data instanceof Array && data.length) {
          data.forEach(itm => {
            this.$set(itm, 'value', itm[this.props.value]);
            this.$set(itm, 'label', itm[this.props.label]);
            this.$set(itm, this.props.value, itm[this.props.value]);
            this.$set(itm, this.props.label, itm[this.props.label]);
            if(!this.value.includes(itm[value])) {
              this.value.push(itm)
            }
            if (this.optionsData.findIndex(i => i[value] === itm[value]) === -1) {
              this.optionsData.push(itm);
            }
          });
          let values = arr(this.value).pluck(this.props.value).all()
          this.dataChange(Array.from(new Set(values)))
        } else {
          if (this.optionsData.findIndex(i => i[value] === data[value]) === -1) {
            this.optionsData.push(data);
          }
          this.labelValue = data[value]
          this.dataChange(this.labelValue)
        }
      },
      // 搜索数据
      dataFilter(val) {
        this.$set(this.params, this.searchKey, val);
        this.getAsyncOptions();
      }
    }
  };
</script>

<style scoped lang="scss">
  .active-search-icon{
    color: #1890ff !important;
    font-weight: bold;
  }
  .active-search-icon :hover{
    color: #1890ff22 !important;
    font-weight: bold;
  }
  .select-data-container {
    position: relative;
    /deep/ .el-input {
      &:hover {
        cursor: pointer;
      }
      input {
        &:hover {
          cursor: pointer;
        }
      }
    }
    .select-box {
      position: relative;
      .icon {
        cursor: pointer;
        color: #c0c4cc;
        position: absolute;
        right: 10px;
        top: 50%;
        transform: translateY(-50%);
      }
    }
    /deep/ .el-select {
      width: 100%;
      height: 100%;
      display: block;
      position: relative;
      .el-input__suffix {
        display: none;
        .el-icon-arrow-up {
          display: none;
        }
      }
      &:hover .el-input__suffix {
        display: inline;
        margin-right: 16px;
      }
    }
    /deep/ .is-disabled .el-input__inner {
      color: #4d4d4d;
    }


  }
  .select-tree {
    display: none;
  }
  ::v-deep.el-select-dropdown__list{
    display: none !important;
  }
  >>> .el-select-dropdown__list {
    display: none !important;
  }
</style>
